package cn.qdhlm.collectservice.core.component;


import cn.qdhlm.collectservice.common.Constant;
import cn.qdhlm.collectservice.common.helper.RedisHelper;
import cn.qdhlm.collectservice.common.util.ComUtil;
import cn.qdhlm.collectservice.common.util.JsonUtil;
import cn.qdhlm.collectservice.core.component.command.*;
import cn.qdhlm.collectservice.model.dto.CommandParamDTO;
import cn.qdhlm.collectservice.model.rocketmq.TerminalData;
import cn.qdhlm.collectservice.service.UtilityService;
import io.netty.buffer.ByteBuf;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @Name: Commander
 * @Description: Commander
 * @Author: jiangcs
 */
@Log4j2
@Component
public class Commander {

    @Autowired
    private UtilityService utilityService;

    /**
     * 执行 命令
     *
     * @param afn
     * @param fn
     * @param commandParamDTO
     * @return
     */
    public String execute(String afn, String fn, CommandParamDTO commandParamDTO) {
        if (ComUtil.isEmpty(commandParamDTO)){
            return "参数不能为空";
        }
        log.info("execute: afn[{}], fn[{}]", afn, fn);

        // 命令序号
//        int nextSn = RedisHelper.nextSN("EX_NB_" + commandParamDTO.getTerminalNo(), Constant.SN_MAX_COMMAND);
        int nextSn = 0;
        // pack
        ByteBuf byteBuf = packages(nextSn, afn, fn, commandParamDTO);
        if (ComUtil.isEmpty(byteBuf) || byteBuf.readableBytes() == 0) {
            return "组了个空包";
        }
        String terminalNo = "";
        // 获取terminalNo
        try {
            String protocolCode = utilityService.getProtocolCode(commandParamDTO.getCodeCustomNB());
            int protocolType = utilityService.getProtocolType(protocolCode);
            terminalNo = utilityService.getTerminalNo(protocolType, protocolCode, null, commandParamDTO.getMacAddr());
        }catch (Exception e){
            e.printStackTrace();
            return "协议异常";
        }

        // 发送命令
        utilityService.sendCommand(terminalNo, nextSn, commandParamDTO.getMacAddr()
                , commandParamDTO.getCodeCustomNB(), afn + "/" + fn, byteBuf);

        return "组包成功";
    }

    /**
     * 处理 待发送 命令
     *
     * @param terminalData
     */
    public boolean deal(TerminalData terminalData) {
        return true;
    }

    /**
     * 休眠命令
     *
     * @param terminalData
     */
    // 0c/2
    public void sleep(TerminalData terminalData) {
        // 命令序号
        int nextSn = RedisHelper.nextSN("EX_NB_" + terminalData.getTerminalNo(), Constant.SN_MAX_COMMAND);

        log.info("sleep[{}] send begin ...", nextSn);

        // pack
        ByteBuf byteBuf = packages(nextSn, "0c", "2", null);
    }

    /**
     * 组包
     *
     * @param sn
     * @param afn
     * @param fn
     * @param commandParamDTO
     * @return
     */
    private ByteBuf packages(int sn, String afn, String fn, CommandParamDTO commandParamDTO) {
        // 终端信息
        String macAddr = commandParamDTO.getMacAddr();
        Integer codeCustomNB = commandParamDTO.getCodeCustomNB();
        if (ComUtil.isEmpty(macAddr)) {
            log.error("packages fail: macAddr is null");
            return null;
        }
        if (ComUtil.isEmpty(codeCustomNB)) {
            log.error("packages fail: codeCustomNB is null");
            return null;
        }

        // 数据包
        ByteBuf byteBuf = null;

        switch (afn) {
            // 设置命令
            case "03":
                switch (fn) {
                    case "1":
                        // ip,port
                        byteBuf = CmdAfn03.f1(sn, commandParamDTO);
                        break;
                    case "3":
                        // dateTime
                        byteBuf = CmdAfn03.f3(sn, commandParamDTO);
                        break;
                    case "4":
                        // uploadMode,startTime,endTime
                        byteBuf = CmdAfn03.f4(sn, commandParamDTO);
                        break;
                    case "5":
                        // collectMode,interval,timing1,timing2
                        byteBuf = CmdAfn03.f5(sn, commandParamDTO);
                        break;
                    case "6":
                        // macAddr
                        byteBuf = CmdAfn03.f6(sn, codeCustomNB, commandParamDTO);
                        break;
                    case "31":
                        // correctTemperature,correctHumidity
                        byteBuf = CmdAfn03.f31(sn, commandParamDTO);
                        break;
                    case "32":
                        // correctTemperature
                        byteBuf = CmdAfn03.f32(sn, commandParamDTO);
                        break;
                    // 配置下发-NB测量点
                    case "250":
                        // uploadMode,startTime,endTime,uploadCycle,collectMode,interval,timing1,timing2,ip,port
                        byteBuf = CmdAfn03.f250(sn, commandParamDTO);
                        break;
                    case "251":
                        // uploadMode,startTime,endTime,uploadCycle,collectMode,interval,timing1,timing2,ip,port
                        byteBuf = CmdAfn03.f251(sn, codeCustomNB, macAddr, commandParamDTO);
                        break;
                    // 配置下发-NB表阀
                    case "254":
                        // uploadMode,startTime,endTime,collectMode,interval,timing1,timing2,ip,port
                        byteBuf = CmdAfn03.f254(sn, commandParamDTO);
                        break;
                    case "255":
                        // uploadMode,startTime,endTime,collectMode,interval,timing1,timing2,ip,port
                        byteBuf = CmdAfn03.f255(sn, codeCustomNB, macAddr, commandParamDTO);
                        break;
                    default:
                        log.error("packages: afn[{}], fn[{}] match fail", afn, fn);
                }
                break;
            // 查询参数
            case "05":
                switch (fn) {
                    case "1":
                        byteBuf = CmdAfn05.f1(sn);
                        break;
                    case "3":
                        byteBuf = CmdAfn05.f3(sn);
                        break;
                    case "4":
                        byteBuf = CmdAfn05.f4(sn);
                        break;
                    case "5":
                        byteBuf = CmdAfn05.f5(sn);
                        break;
                    case "6":
                        byteBuf = CmdAfn05.f6(sn);
                        break;
                    case "7":
                        byteBuf = CmdAfn05.f7(sn);
                        break;
                    case "8":
                        byteBuf = CmdAfn05.f8(sn);
                        break;
                    case "9":
                        byteBuf = CmdAfn05.f9(sn);
                        break;
                    case "255":
                        byteBuf = CmdAfn05.f255(sn);
                        break;
                    default:
                        log.error("packages: afn[{}], fn[{}] match fail", afn, fn);
                }
                break;
            // 1类数据
            case "0a":
                switch (fn) {
                    case "1":
                        byteBuf = CmdAfn0a.f1(sn);
                        break;
                    default:
                        log.error("packages: afn[{}], fn[{}] match fail", afn, fn);
                }
                break;
            // 控制
            case "0c":
                String protocolCode = commandParamDTO.getProtocolCode();
                // 根据协议code获取终端类型：默认0x46
                String deviceType = "46";
                // 京源IC卡超声波热量表：0x20
                if ("CJT188_0053".equals(protocolCode)) {
                    deviceType = "20";
                }
                // WAC500_NB电信调节阀：0x50
                else if ("EN1434_9985".equals(protocolCode)) {
                    deviceType = "50";
                }

                switch (fn) {
                    case "1":
                        byteBuf = CmdAfn0c.f1(sn, deviceType, macAddr);
                        break;
                    // 休眠
                    case "2":
                        byteBuf = CmdAfn0c.f2(sn);
                        break;
                    // 强制设温（NBT200-AC）
                    case "3":
                        byteBuf = CmdAfn0c.f3(sn, commandParamDTO);
                        break;
                    // 解锁
                    case "4":
                        byteBuf = CmdAfn0c.f4(sn);
                        break;
                    // 写累计工作时间（NBT200-AC）
                    case "5":
                        byteBuf = CmdAfn0c.f5(sn, commandParamDTO);
                        break;
                    // 写供暖期（益都热表(NB)）
                    case "6":
                        byteBuf = CmdAfn0c.f6(sn, commandParamDTO);
                        break;
                    // 读供暖期（益都热表(NB)）
                    case "7":
                        byteBuf = CmdAfn0c.f7(sn);
                        break;
                    // 写阀门控制：强开（调节阀 + 锁闭阀）
                    case "55":
                        // 写阀门控制：普开（调节阀）
                    case "66":
                        // 写阀门控制：普关（调节阀）
                    case "77":
                        // 写阀门控制：清洗（调节阀）
                    case "88":
                        // 写阀门控制：强关（调节阀 + 锁闭阀）
                    case "99":
                        // 写阀门控制：自由控制（调节阀 + 锁闭阀）
                    case "ff":
                        byteBuf = CmdAfn0c.fA017(sn, deviceType, macAddr, fn);
                        break;
                    // 写是否启用温差、回温调节（调节阀）
                    case "ac03":
                        byteBuf = CmdAfn0c.fAc03(sn, deviceType, macAddr, commandParamDTO);
                        break;
                    // 写目标调节值（调节阀）
                    case "ac04":
                        byteBuf = CmdAfn0c.fAc04(sn, deviceType, macAddr, commandParamDTO);
                        break;
                    // 写阀门开度上下限（调节阀）
                    case "a028":
                        byteBuf = CmdAfn0c.fA028(sn, deviceType, macAddr, commandParamDTO);
                        break;
                    // 写阀门所有配置参数（调节阀）
                    case "ac01":
                        // 设置温度偏差（NBT200测温插座）
                        if ("EN1434_9988".equals(protocolCode)) {
                            byteBuf = CmdAfn0c.fAc014EN14349988(sn, deviceType, macAddr, commandParamDTO);
                        }
                        // 写阀门所有配置参数（调节阀）
                        else {
                            byteBuf = CmdAfn0c.fAc01(sn, deviceType, macAddr, commandParamDTO);
                        }
                        break;
                    // 读阀门所有配置参数（调节阀）
                    case "ab01":
                        // 读温度偏差（NBT200测温插座）
                        if ("EN1434_9988".equals(protocolCode)) {
                            byteBuf = CmdAfn0c.fAb014EN14349988(sn, deviceType, macAddr);
                        }
                        // 读阀门所有配置参数（调节阀）
                        else {
                            byteBuf = CmdAfn0c.fAb01(sn, deviceType, macAddr);
                        }
                        break;
                    // 写清洗阀门周期（锁闭阀）
                    case "a02c":
                        byteBuf = CmdAfn0c.fA02c(sn, deviceType, macAddr, commandParamDTO);
                        break;
                    // 读清洗阀门周期（锁闭阀）
                    case "a02d":
                        byteBuf = CmdAfn0c.fA02d(sn, deviceType, macAddr);
                        break;
                    // 写充值信息（锁闭阀）
                    case "ac05":
                        byteBuf = CmdAfn0c.fAc05(sn, deviceType, macAddr, commandParamDTO);
                        break;
                    // 读充值信息（锁闭阀）
                    case "ab05":
                        byteBuf = CmdAfn0c.fAb05(sn, deviceType, macAddr);
                        break;
                    // 充值信息清除（锁闭阀）
                    case "ac07":
                        byteBuf = CmdAfn0c.fAc07(sn, deviceType, macAddr);
                        break;
                    // 写充值水量信息（锁闭阀）
                    case "a101":
                        byteBuf = CmdAfn0c.fA101(sn, deviceType, macAddr, commandParamDTO);
                        break;
                    // 查询水量充值记录（锁闭阀）
                    case "a201":
                        byteBuf = CmdAfn0c.fA201(sn, deviceType, macAddr);
                        break;
                    // 撤销某次水量充值（锁闭阀）
                    case "a102":
                        byteBuf = CmdAfn0c.fA102(sn, deviceType, macAddr, commandParamDTO);
                        break;
                    // 管理卡（京源IC卡阀控热表(NB)）
                    case "1020":
                        deviceType = "55";

                        byteBuf = CmdAfn0c.f1020(sn, deviceType, macAddr);
                        break;
                    default:
                        log.error("packages: afn[{}], fn[{}] match fail", afn, fn);
                }
                break;
            default:
                log.error("packages: afn[{}] match fail", afn);
        }

        if (byteBuf != null) {
            // hex string
            return CmdCom.pack(commandParamDTO.getMacAddr(), commandParamDTO.getCodeCustomNB(), byteBuf);
        }
        return null;
    }

    /**
     * 发送命令
     *
     * @param exNBCommand
     */
    /*private void send4Emqx(ExNBCommand exNBCommand) {
        if (exNBCommand == null) {
            log.error("exNBCommand is empty");
            return;
        }

        // mqtt状态
        String exStatus;
        // 状态：1-执行中；3-执行失败
        int status;
        // 发送时间
        Date sendTime = new Date();
        Update update = new Update();

        // NB_Client/${codeCustomNB}/${macAddr}
        String topic = "NB_Client/" + ComUtil.fillZeroLeft(exNBCommand.getCodeCustomNB(), 3) + "/" + exNBCommand.getMacAddr();
        boolean publishFlag = MqttHelper.publish(topic, CodeUtil.base64StringToByteArray(exNBCommand.getData()));
        if (publishFlag) {
            exStatus = "SENT";
            status = 1;
        } else {
            exStatus = "FAIL";
            status = 3;
        }

        log.info("send exNBCommand: mongoId[{}], status[{}], exStatus[{}], data[{}]", exNBCommand.getId(), status, exStatus, exNBCommand.getData());

        // 更新 mongodb命令状态
        update.set("status", exStatus);
        update.set("sendTime", sendTime);
        update.set("updateTime", new Date());
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(exNBCommand.getId()));
        boolean updateFlag = MongoHelper.updateFirst(query, update, ExNBCommand.class);
        log.info("update exNBCommand[{}]: {}", exNBCommand.getId(), updateFlag);

        String funcCode = exNBCommand.getFuncCode();
        if (Constant.FUNC_CODE_SLEEP.equals(funcCode)) {
            log.info("sleep command end");
            return;
        }

        Integer commandTerminalId = exNBCommand.getCommandTerminalId();
        if (ComUtil.isEmpty(commandTerminalId)) {
            log.error("commandTerminalId is null");
            return;
        }

        int count = commandTerminalMapper.updateSendResultStatus(commandTerminalId, sendTime, exStatus, status);
        if (count <= 0) {
            log.error("commandTerminalMapper.updateSendResultStatus fail");
        }

        // 执行中命令，设备回执结果处理
        if (status == 1) {
            processTimeout(commandTerminalId, ExNBCommand.class);
        }
    }*/

    /**
     * 处理 命令超时：20s 设备没有回执
     *
     * @param commandTerminalId
     * @param clazz
     */
/*    private void processTimeout(Integer commandTerminalId, Class clazz) {
        ThreadPoolHelper.getScheduledInstance().schedule(() -> {
            Integer status = commandTerminalMapper.getStatusById(commandTerminalId);
            if (ComUtil.isEmpty(status)) {
                log.error("process timeout: command status get fail");
                return;
            }

            if (status == Constant.COMMAND_STATUS_2) {
                // 更新 mongodb 命令状态为 SUCCESS
                updateCommandStatus(commandTerminalId, "SUCCESS", null, null, null, clazz);
            } else if (status == Constant.COMMAND_STATUS_1) {
                // 更新 mongodb 命令状态为 20-SECONDS-TIMEOUT
                updateCommandStatus(commandTerminalId, "20-SECONDS-TIMEOUT", "20-SECONDS-TIMEOUT", "等待响应超时：等待时间20秒", 3, clazz);
            }
        }, 20, TimeUnit.SECONDS);
    }*/

    /**
     * 更新 当前命令状态
     *
     * @param commandTerminalId
     * @param exStatus
     * @param result
     * @param resultZH
     * @param status
     * @param clazz
     * @return
     */
/*    private void updateCommandStatus(Integer commandTerminalId, String exStatus, String result, String resultZH, Integer status, Class clazz) {
        if (!ComUtil.isEmpty(commandTerminalId)) {
            if (!ComUtil.isEmpty(result) && !ComUtil.isEmpty(resultZH) && !ComUtil.isEmpty(status)) {
                int count = commandTerminalMapper.updateResultStatus(commandTerminalId, result, resultZH, status);
                log.info("updateCommandStatus: update commandTerminalId[{}], status[{}]: {}", commandTerminalId, status, count);
            }

            Query query = new Query();
            query.addCriteria(Criteria.where("commandTerminalId").is(commandTerminalId))
                    .addCriteria(Criteria.where("status").is("SENT"));
            Update update = new Update();
            update.set("status", exStatus);
            boolean updateFlag = MongoHelper.updateFirst(query, update, clazz);
            log.info("updateCommandStatus: update mongodb commandTerminalId[{}], result[{}]", commandTerminalId, updateFlag);
        } else {
            log.error("updateCommandStatus：commandTerminalId is null");
        }
    }*/
}
